#include "stdafx.h" 

#include <map> 

#include <string.h>


#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

#include "readCfg.h"

#include "./MD5.h"

#include "./fore_rtdb.h"

#include "./rapidjson/rapidjson.h" 
#include "./rapidjson/document.h" 
#include "./rapidjson/writer.h" 
#include "./rapidjson/stringbuffer.h" 
#include "./rapidjson/prettywriter.h" 
#include "./rapidjson/filereadstream.h"
#include "./rapidjson/filewritestream.h"

using namespace std;

using namespace rapidjson;
 
int dbmsRecv_Msgarrvd(void *context, char *topicName, int topicLen, MQTTAsync_message *message);

CReadCfg::CReadCfg()
{  
	ClearVector();
 
}

CReadCfg::~CReadCfg() 
{
	 
}

void CReadCfg::ClearVector()
{ 
	m_aryServiceObjs.clear();
}
  
int dbmsRecv_Msgarrvd(void *context, char *topicName, int topicLen, MQTTAsync_message *message)
{
	CReadCfg * pReadCfg = (CReadCfg*)context;
	 
		
	MQTTAsync_freeMessage(&message);
	MQTTAsync_free(topicName);  

	return 1;
}


string  get_file_code(char * filepathname)
{
	if( filepathname == NULL ) return "";

	struct stat statbuff; 
	string  strCode;

	XCollector   colFileData; 
    	if(stat(filepathname, &statbuff) == 0)
	{    
		colFileData.SetSize(statbuff.st_size); 

		FILE *fp;  
		if( (fp=fopen( filepathname,"rb" )) != NULL){  
			fread((char*)colFileData.GetData(), statbuff.st_size, 1, fp);  
			fclose( fp ); 
		} 
    	}   

	if( colFileData.GetSize() > 0 ) {
		//CMD5Encode encode_obj;  
		strCode = CMD5Encode::MD5Encode( (char*)colFileData.GetData(), colFileData.GetSize() );
	}
//base::my_printf("code=%s \n", strCode.c_str() );

	return strCode; 
}

void CReadCfg::process_rtdb()
{  
	base::my_printf( "analyse begin......\n"); 
	 
	char	processdir[128] = {0};
	char	processname[128] = {0};
	char	profile_devtype_filename[128] = {0}; 
	size_t sz = base::get_executable_path(processdir, processname, 128);
	if( sz <= 0 ) return   ; 
 
	std::vector<FORE_DEV_TYPE>  aryDevType;

	LoadDevTypeCfg(aryDevType);

	for( int i=0; i<aryDevType.size(); i++ )
	{
		FORE_DEV_TYPE & devType = aryDevType[i];

		base::my_printf( "begin load devtype=%s  profilename=%s ....!\n", devType.dev_type, devType.profilename ); 

		if( strlen(devType.profilename) <= 0 ) continue;

		if( strstr(devType.profilename, ".json") > 0 ) {
			char  pathBuf[128]={0};  
		 
		 	sprintf(pathBuf, "%s/%s", processdir, devType.profilename ); 
		 

			if( !base::is_exist_file(pathBuf) ) {
				base::my_printf( "error:%s is not exist !! \n", pathBuf ); 
				continue;
			} 

			string  strfilecode = get_file_code(pathBuf);

			base::my_printf("\n code=%s, len=%d \n", strfilecode.c_str(), strfilecode.size() );

			char chrCode[48] = {0};  
			FORE_PARAM_CFG * recParam = (FORE_PARAM_CFG*)FindRec_stringkey(FORE_PARAM_CFG_NO, devType.profilename); 
			if( recParam ) { 
				strcpy(chrCode, recParam->param_val); 
			}

			if(  strcmp(strfilecode.c_str(), chrCode ) == 0 ) {
				base::my_printf( "(%s):(%s) : is same code 2 \n", strfilecode.c_str(), chrCode );

				continue; 
			} 

			TDbFun::remove_mev_by_dev_type( devType.dev_type );

			FORE_PARAM_CFG   param; 
			strcpy(param.param_name, devType.profilename);

			strcpy(param.param_val, strfilecode.c_str());

	 		if( ! UpdateRec_stringkey_Ex(FORE_PARAM_CFG_NO, devType.profilename, (char*)&param, sizeof(FORE_PARAM_CFG)  ) ) {
				base::my_printf( " update param error : %s   \n", devType.profilename);

				continue;
			}


			//load profile 
			if(  load_dev_model_json(pathBuf, devType) ) {   
				 
				if( m_aryServiceObjs.size() > 0 ) { 
					InsertProfileToRtdb();
					ClearVector();  
				}
				else {
					base::my_printf( "m_aryServiceObjs  size=0 \n" ); 	 
				} 
			}  
		}
	 
  
	}
	 
	base::my_printf( "-------------analyse end-------------\n"); 

	//read_param();
}

 
bool CReadCfg::InsertProfileToRtdb( )
{  	 
	if( m_aryServiceObjs.size() <= 0 ) return false;
	
	for( int i=0; i<m_aryServiceObjs.size(); i++ )
	{
		STRU_PROFILE_SERVICEID & serviceObj = m_aryServiceObjs[i];

		FORE_DEV_TYPE * pDevTypeRec = (FORE_DEV_TYPE*)FindRec_stringkey(FORE_DEV_TYPE_NO, serviceObj.deviceType);
		if( pDevTypeRec == NULL ) {
			base::my_printf( "not find devtype=%s    \n", serviceObj.deviceType);  
			continue; 
		}

		strcpy(pDevTypeRec->manufacturerName, serviceObj.manufacturerName);
		strcpy(pDevTypeRec->manufacturerId, serviceObj.manufacturerId);
		strcpy(pDevTypeRec->model, serviceObj.model);
		strcpy(pDevTypeRec->protocolType, serviceObj.protocolType);
		strcpy(pDevTypeRec->deviceType, serviceObj.deviceType);
		strcpy(pDevTypeRec->omCapability, serviceObj.omCapability);


		for (int j=0; j<serviceObj.aryProperty.size(); j++) 
		{   
			STRU_PROPERTY & propertyObj = serviceObj.aryProperty[j];
 
			FORE_MEA_TEMPLATE     meaTempl;

			strcpy(meaTempl.dev_type, serviceObj.deviceType);
			strcpy(meaTempl.serviceid, serviceObj.serviceId);
 
			strcpy(meaTempl.propertyName, propertyObj.propertyName); 
			meaTempl.required = propertyObj.required;
			strcpy(meaTempl.min, propertyObj.min); 
			strcpy(meaTempl.max, propertyObj.max); 
			meaTempl.step = propertyObj.step;
			meaTempl.maxLength = propertyObj.maxLength;
			strcpy(meaTempl.method, propertyObj.method); 
			strcpy(meaTempl.unit, propertyObj.unit); 
			strcpy(meaTempl.dataType,  propertyObj.dataType);
			meaTempl.zf_type = propertyObj.zfType;

			char  chrKey[32] = {0};
			sprintf(chrKey, "%s:%s", meaTempl.dev_type, meaTempl.propertyName);


			UpdateRec_stringkey_Ex(FORE_MEA_TEMPLATE_NO, chrKey , (char*)&meaTempl, sizeof(FORE_MEA_TEMPLATE)  ) ; 
		}
	}
 

	


	return true;
}
 
 


 
 

bool CReadCfg::LoadDevTypeCfg( std::vector<FORE_DEV_TYPE> & aryDevType )
{
	//printf("/mnt/nand/paramCfg/param/devTypeCfg.xml \n ");
	//string strDevTypeCfg = "/mnt/nand/paramCfg/param/devTypeCfg.xml";
	char  devTypeCfgPath[128] = {0};
	//sprintf(devTypeCfgPath, "%s/devTypeCfg.xml",  paramPath);
	strcpy(devTypeCfgPath, "./devTypeCfg.xml");
	tinyxml2::XMLDocument  doc; 
	if( doc.LoadFile(devTypeCfgPath ) != 0 ) {  
		char log[128]; 
		sprintf(log, "%s Load Error : errorID= %s \n",  devTypeCfgPath,  doc.ErrorStr() );  
		base::my_printf( log );  
		doc.Clear();
		return  false; 
	} 
	 
	////////////////////  
	try  
	{ 
		tinyxml2::XMLElement*config = doc.RootElement();//config����
    	tinyxml2::XMLElement*termType = config->FirstChildElement();//RootElement

		
		while(termType != NULL)
		{
		 	tinyxml2::XMLElement*term = termType->FirstChildElement();//����

			while(term != NULL)
    			{   
				FORE_DEV_TYPE   addrtype;
				memset(&addrtype, 0, sizeof(FORE_DEV_TYPE));

				string strID = term->Attribute("id");

				base::my_printf("id=%s \n", strID.c_str() );  

				addrtype.termtype = atoi( term->Attribute("id") ); 

				strcpy(addrtype.dev_type, term->Attribute("dev_type") ); 
				base::my_printf("addrtype.dev_type=%s \n", addrtype.dev_type);  
				 
				strcpy(addrtype.profilename, term->Attribute("profilename") );  
				base::my_printf("profilename=%s \n", addrtype.profilename);  

				const char * pUpInterval = term->Attribute("UpInterval");
				if( pUpInterval ) {
					base::my_printf("pUpInterval=%s \n", pUpInterval);  
					addrtype.Reporting_interval = atoi( pUpInterval );  
				}
				if( addrtype.Reporting_interval == 0 ) addrtype.Reporting_interval = 300;

				aryDevType.push_back(addrtype);

				FORE_DEV_TYPE * pDevTypeRec = (FORE_DEV_TYPE*)FindRec_stringkey(FORE_DEV_TYPE_NO, addrtype.dev_type);
				if( pDevTypeRec == NULL ) {
					 UpdateRec_stringkey_Ex(FORE_DEV_TYPE_NO, addrtype.dev_type, (char*)&addrtype, sizeof(FORE_DEV_TYPE)  ) ;
				}
				else {
					 
					addrtype.termtype = atoi( term->Attribute("id") );  
					strcpy(pDevTypeRec->profilename, addrtype.profilename);

					if( pUpInterval ) {
						pDevTypeRec->Reporting_interval = atoi( pUpInterval );  
					}
					if( pDevTypeRec->Reporting_interval == 0 ) pDevTypeRec->Reporting_interval = 300;
				}

			

				term = term->NextSiblingElement();
			} 
			termType = termType->NextSiblingElement();
		}
		
	} 
	catch(...) { 
		return false;
	}
	
	doc.Clear();
	 
	return true;	
}
  


 
bool CReadCfg::load_dev_model_json(char* profile_devtype_filename, FORE_DEV_TYPE & devType )
{ 
	//char	processdir[128] = {0};
	//char	processname[128] = {0};
	//char	profile_devtype_filename[128] = {0};
	char	service_filename[128] = {0};
	
 
	/*size_t sz = base::get_executable_path(processdir, processname, 128);
	if( sz <= 0 ) return false ; 
 
 	sprintf(profile_devtype_filename, "%s/%s", processdir, devType.profilename ); 
 

	if( !base::is_exist_file(profile_devtype_filename) ) {
		base::my_printf( "error:%s is not exist !! \n", profile_devtype_filename ); 
		return  false;
	}*/

	struct stat statbuff; 

	XCollector   colFileData; 
    	if(stat(profile_devtype_filename, &statbuff) == 0)
	{    
		colFileData.SetSize(statbuff.st_size); 

		FILE *fp;  
		if( (fp=fopen( profile_devtype_filename,"rb" )) != NULL){  
			fread((char*)colFileData.GetData(), statbuff.st_size, 1, fp); 
			fclose( fp ); 
		} 
    	}    

	if( colFileData.GetSize() <= 0  ) return false;
 
	try
	{  
		//anlise_json
		rapidjson::Document newDoc; 
		newDoc.Parse((char*)colFileData.GetData());

		if (newDoc.HasParseError()) {
			base::my_printf( "Json Parse error:%d \n", newDoc.GetParseError()); //��ӡ������
			newDoc.Clear();
			return false;
		}
		else { 
			if (!newDoc.HasMember("services")) { 
				base::my_printf( " [services] is not exist \n" );  	
				newDoc.Clear();
				return false;
			}  

			if( newDoc["deviceType"].IsNull() ) {
				base::my_printf( " [deviceType] is not exist \n" );  	
				newDoc.Clear();
				return false;
			}

			string  strdevType = newDoc["deviceType"].GetString() ;
			base::my_printf( " deviceType=%s \n", strdevType.c_str() ); 
			 
			if( strcmp(devType.dev_type, strdevType.c_str()) != 0 ) { 
				base::my_printf( " Inconsistent device types !!! \n" );  	
				newDoc.Clear();
				return false;
			}
 
			rapidjson::Value ary_service_data;
			ary_service_data = newDoc["services"]; 

			for (rapidjson::SizeType i = 0; i < ary_service_data.Size(); i++) { 
				rapidjson::Value & serverTypeObject = ary_service_data[i];  
			 
				STRU_PROFILE_SERVICEID   serviceObj;
				strcpy(serviceObj.deviceType, devType.dev_type);

				base::my_printf("services : [ \n" ); 
 
				string  strServeiceId;
				strServeiceId = serverTypeObject["serviceId"].GetString() ;
				base::my_printf( " serviceId=%s \n", strServeiceId.c_str() ); 
 
				strcpy(serviceObj.serviceId, strServeiceId.c_str());

				if (serverTypeObject.HasMember("properties")) { 

					rapidjson::Value ary_properties;
					ary_properties = serverTypeObject["properties"]; 

					base::my_printf( "properties : [ \n" ); 

					 
					rapidjson::Value properties_item_data;
					for (rapidjson::SizeType j = 0; j < ary_properties.Size(); j++) { 
						properties_item_data = ary_properties[j];  
					 
						base::my_printf(  " {  \n" ); 

						STRU_PROPERTY    propertyObj;
						strcpy(propertyObj.propertyName, properties_item_data["name"].GetString());
						base::my_printf( " name=%s \n", propertyObj.propertyName ); 

						if( !properties_item_data["datatype"].IsNull() ) {
							strcpy(propertyObj.dataType, properties_item_data["datatype"].GetString());
							base::my_printf( " datatype=%s \n", propertyObj.dataType ); 
						}

						if( !properties_item_data["required"].IsNull() ) {
							propertyObj.required = properties_item_data["required"].GetBool() ;
							base::my_printf( " required=%d \n", (int)propertyObj.required ); 
						}

						if( !properties_item_data["min"].IsNull() ) {
							strcpy(propertyObj.min, properties_item_data["min"].GetString());
							base::my_printf( " min=%s \n", propertyObj.min ); 
						}

						if( !properties_item_data["max"].IsNull() ) {
							strcpy(propertyObj.max, properties_item_data["max"].GetString());
							base::my_printf( " max=%s \n", propertyObj.max ); 
						}

						if( !properties_item_data["step"].IsNull() ) {
							propertyObj.step = properties_item_data["step"].GetFloat();
							base::my_printf( " step=%0.2f \n", propertyObj.step ); 
						}

						if( !properties_item_data["maxlength"].IsNull() ) {
							propertyObj.maxLength = properties_item_data["maxlength"].GetInt();
							base::my_printf(  " maxlength=%d \n", propertyObj.maxLength ); 
						}

						if( !properties_item_data["unit"].IsNull() ) {
							strcpy(propertyObj.unit, properties_item_data["unit"].GetString());
							base::my_printf(  " unit=%s \n", propertyObj.unit ); 
						}

						if( !properties_item_data["method"].IsNull() ) {
							strcpy(propertyObj.method, properties_item_data["method"].GetString());
							base::my_printf(  " method=%s \n", propertyObj.max ); 
						}

						if( !properties_item_data["zfType"].IsNull() ) {
							propertyObj.zfType = properties_item_data["zfType"].GetInt() ;
							base::my_printf(  " zfType=%d \n", propertyObj.zfType ); 
						}

						base::my_printf( " }  \n" ); 

						serviceObj.aryProperty.push_back( propertyObj ); 
						 
					}


					base::my_printf(  "   ] \n" ); 
				}
				else {
					base::my_printf( " [properties] is not exist \n" );  
					continue;
				} 

				if( serviceObj.aryProperty.size() > 0 ) 
					m_aryServiceObjs.push_back( serviceObj ); 
			   
				base::my_printf( "] \n" ); 
			}
		}

		newDoc.Clear();

		return true;
	}
	catch(...) {
	} 

	return false;

}





